﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
using WeifenLuo.WinFormsUI.Docking;
using System.Threading;

namespace RescueRobotController.Panels
{
    public partial class SerialPortTerminalPanel : DockContent, IReceivedATCmd
    {
        private string appendText = "";
        private SerialPort serialPort = null;
        private Thread watchSerialStateThread = null;
        private bool watchSerialStateThreadRunning = true;
        private int currentSerialIndex = 0;

        /* 下面的内容是每个面板必须要有的 */
        // *********** BEGIN ************* //
        // “发送AT指令”事件
        public delegate void ExistATCmdToSendHandler(ATCmd cmd);
        public event ExistATCmdToSendHandler SendATCmd;

        // 处理AT指令
        public void HandleATCmd(ATCmd cmd)
        {

        }
        // *********** END ************* //

        public SerialPortTerminalPanel()
        {
            InitializeComponent();
            serialPort = new SerialPort();
            CheckForIllegalCrossThreadCalls = false;
            LoadPortNames();
            watchSerialStateThread = new Thread(WatchSerialStateTask);
        }

        public void AppendString(string str)
        {
            text_received.AppendText(str);
        }

        public SerialPort GetSerialPort()
        {
            return serialPort;
        }
        private void WatchSerialStateTask()
        {
            while (watchSerialStateThreadRunning)
            {
                if (serialPort != null)
                {
                    if (!serialPort.IsOpen)
                    {
                        // 串口处于关闭状态
                        btn_openclose_serial.Invoke(new Action(() => {
                            btn_openclose_serial.Text = "打开串口";
                            btn_openclose_serial.ForeColor = Color.Black;
                        }));
                        Common.isSerialOpened = false;

                        combo_serialname.Invoke(new Action(() =>
                        {
                            combo_serialname.Enabled = true;
                        }));
                        
                    }
                    else
                    {
                        btn_openclose_serial.Invoke(new Action(() => {
                            btn_openclose_serial.Text = "关闭串口";
                            btn_openclose_serial.ForeColor = Color.Red;
                        }));
                        Common.isSerialOpened = false;
                        combo_serialname.Invoke(new Action(() =>
                        {
                            combo_serialname.Enabled = false;
                        }));
                    }
                }
                else
                {
                    // 如果串口是null，就什么都不做
                }
            }
        }

        private void SerialPortTerminal_Load(object sender, EventArgs e)
        {
            // 串口终端面板刚刚加载的时候
            combo_append.SelectedIndex = 0;
            combo_baudrate.SelectedIndex = 13;
            combo_databits.SelectedIndex = 0;
            combo_parity.SelectedIndex = 0;
            combo_stopbit.SelectedIndex = 0;

            if (combo_serialname.Items.Count > 0)
            {
                combo_serialname.SelectedIndex = 0;
            }
            watchSerialStateThread.IsBackground = true;
            watchSerialStateThread.Start();
            serialPort.ErrorReceived += SerialPort_ErrorReceived;
        }

        private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
            MessageBox.Show("串口错误");
        }

        public void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort serial = (SerialPort)sender;
            int bytesToRead = serial.BytesToRead;
            byte[] buffer = new byte[bytesToRead];

            serial.Read(buffer, 0, bytesToRead);
            text_received.AppendText(Encoding.Default.GetString(buffer));
        }

        private void combo_append_SelectedIndexChanged(object sender, EventArgs e)
        {
            /* 附加字符串：
             * 0 - 无附加
             * 1 - 附加"\n"
             * 2 - 附加"\n\r"
             * 3 - 附加"\r\n"
             */
            ComboBox comboBox = (ComboBox)sender;
            int selectedIndex = comboBox.SelectedIndex;
            switch(selectedIndex)
            {
                case 0:
                    appendText = "";
                    break;
                case 1:
                    appendText = "\n";
                    break;
                case 2:
                    appendText = "\n\r";
                    break;
                case 3:
                    appendText = "\r\n";
                    break;
            }
        }

        private void btn_send_Click(object sender, EventArgs e)
        {
            /* 发送按钮点击 */

            string originStr;
            byte[] buffer;

            // 判断串口是否被赋值
            if (serialPort != null)
            {
                if (serialPort.IsOpen) 
                {
                    originStr = text_send.Text + appendText;
                    buffer = Encoding.Default.GetBytes(originStr);
                    serialPort.Write(buffer, 0, buffer.Length);
                }
                else
                {
                    MessageBox.Show("内部错误：串口未开启");
                }
            }
            else
            {
                MessageBox.Show("内部错误：串口不能为null");
            }
        }

        private void OpenSerialPort()
        {
            // 开启串口
            try
            {
                serialPort.Open();
            }
            catch
            {
                MessageBox.Show("串口开启失败");
            }

            if (serialPort.IsOpen)
            {
                btn_openclose_serial.Text = "关闭串口";
                btn_openclose_serial.ForeColor = Color.Red;
                currentSerialIndex = combo_serialname.SelectedIndex;
                combo_serialname.Enabled = false;
            }
        }

        private void CloseSerialPort()
        {
            serialPort.Close();
            btn_openclose_serial.Text = "打开串口";
            btn_openclose_serial.ForeColor = Color.Black;

            // 重加载串口名
            LoadPortNames();
            combo_serialname.Enabled = true;
            combo_serialname.SelectedIndex = currentSerialIndex;
        }

        private void LoadPortNames()
        {
            combo_serialname.Items.Clear();
            foreach (string name in SerialPort.GetPortNames())
            {
                combo_serialname.Items.Add(name);
            }
        }

        private void UpdateSerialConfig()
        {
            //端口名
            serialPort.PortName = combo_serialname.Text;
            //波特率
            serialPort.BaudRate = int.Parse(combo_baudrate.Text);
            //数据位
            serialPort.DataBits = int.Parse((string)combo_databits.Text);
            //校验位
            serialPort.Parity = combo_parity.Text == "None" ? Parity.None :
                        combo_parity.Text == "Odd" ? Parity.Odd :
                        combo_parity.Text == "Even" ? Parity.Even : Parity.None;
            //停止位
            serialPort.StopBits = combo_stopbit.Text == "1" ? StopBits.One :
                        combo_stopbit.Text == "1.5" ? StopBits.OnePointFive :
                        combo_stopbit.Text == "2" ? StopBits.Two : StopBits.One;
        }
        private void btn_openclose_serial_Click(object sender, EventArgs e)
        {
            // 判断是否选择了串口
            if (combo_serialname.SelectedIndex == -1) 
            {
                MessageBox.Show("请先选择一个串口端口");
                return;
            }

            if (serialPort == null)
            {
                serialPort = new SerialPort();
                UpdateSerialConfig();
                // 绑定数据接收事件
            }

            if (serialPort.IsOpen == false)
            {
                UpdateSerialConfig();
                OpenSerialPort();
            }
            else if (serialPort.IsOpen)
            {
                CloseSerialPort();
            }
        }

        private void text_send_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == ((char)Keys.Enter)) btn_send_Click(sender, e);
        }

        private void btn_clear_Click(object sender, EventArgs e)
        {
            text_received.Text = "";
        }

        private void SerialPortTerminalPanel_FormClosing(object sender, FormClosingEventArgs e)
        {
            
        }

        private void btn_refresh_serial_Click(object sender, EventArgs e)
        {
            LoadPortNames();
        }

        private void SerialPortTerminalPanel_FormClosed(object sender, FormClosedEventArgs e)
        {
            //watchSerialStateThreadRunning = false;
            //watchSerialStateThread.Abort();
            CloseSerialPort();
            
        }
    }
}
